﻿using SharpDX;
using SharpDX.DXGI;
using SharpDX.Direct3D;
using SharpDX.Direct3D10;
using Device = SharpDX.Direct3D10.Device1;
using DriverType = SharpDX.Direct3D10.DriverType;
using FeatureLevel = SharpDX.Direct3D10.FeatureLevel;
using System;
using System.Windows.Forms;
using d2 = SharpDX.Direct2D1;

namespace OpenGameEngine.Base
{
    public class GameBaseHardwareLayer
        : GameBase, IDisposable
    {
        Device _device;
        SwapChain _swapChain;
        Texture2D _backBuffer;
        RenderTargetView _backBufferView;

        public bool IsFullScreen { get { return _swapChain.IsFullScreen; } }

        internal Device Device
        {
            get { return _device; }
        }

        internal Texture2D BackBuffer
        {
            get { return _backBuffer; }
        }

        internal RenderTargetView BackBufferView
        {
            get { return _backBufferView; }
        }

        protected override void Initialize(GameConfiguration config)
        {
            SwapChainDescription desc = new SwapChainDescription()
            {
                BufferCount = 1,
                ModeDescription = new ModeDescription(
                    this.RenderingSize.Width,
                    this.RenderingSize.Height,
                    new Rational(60, 1),
                    Format.R8G8B8A8_UNorm),

                IsWindowed = true,
                OutputHandle = DisplayHandle,
                SampleDescription = new SampleDescription(1, 0),
                SwapEffect = SwapEffect.Discard,
                Usage = Usage.RenderTargetOutput,
                Flags = SwapChainFlags.AllowModeSwitch
            };

            //Device.CreateWithSwapChain(DriverType.Hardware, (DeviceCreationFlags.BgraSupport | DeviceCreationFlags.Debug), desc, out _device, out _swapChain);
            Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport, desc, out _device, out _swapChain);
            Factory factory = _swapChain.GetParent<Factory>();
            factory.MakeWindowAssociation(DisplayHandle, WindowAssociationFlags.None);

            _backBuffer = Texture2D.FromSwapChain<Texture2D>(_swapChain, 0);

            _backBufferView = new RenderTargetView(_device, _backBuffer);
        }

        protected override void BeginDraw(GameTime time)
        {
            base.BeginDraw(time);
            Device.Rasterizer.SetViewports(new Viewport(0, 0, 800, 600));
            Device.OutputMerger.SetTargets(_backBufferView);
        }

        protected override void EndDraw(GameTime time)
        {
            base.EndDraw(time);

            _swapChain.Present(Config.VSync ? 1 : 0, PresentFlags.None);
        }


        /// <summary>
        /// Sets the current displaystate to fullscreen or windowed
        /// </summary>
        /// <param name="fullscreen">True for fullscreen, False for windowed</param>
        public void SetFullScreen(bool fullscreen)
        {
            if (IsFullScreen == fullscreen) return;
            if (_swapChain == null) return;

            // _swapChain.SetFullscreenState(fullscreen, null);  

            _backBufferView.Dispose();

            _swapChain.ResizeBuffers(1, RenderingSize.Width, RenderingSize.Height, Format.R8G8B8A8_UNorm, SwapChainFlags.AllowModeSwitch);
            using (Texture2D bb = Texture2D.FromSwapChain<Texture2D>(_swapChain, 0))
                _backBufferView = new RenderTargetView(Device, bb);
            //ModeDescription mod = new ModeDescription(100, 100, /*Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, */ new Rational(60, 1), Format.R8G8B8A8_UNorm);
            //_swapChain.ResizeTarget(ref mod);           
        }

        public void Dispose()
        {
            if (_backBufferView != null)
                if (!_backBufferView.IsDisposed)
                    _backBufferView.Dispose();

            if (_device != null)
                if (!_device.IsDisposed)
                    _device.Dispose();

            if (_swapChain != null)
                if (!_swapChain.IsDisposed)
                    _swapChain.Dispose();

            if (_backBuffer != null)
                if (!_backBuffer.IsDisposed)
                    _backBuffer.Dispose();

            Dispose(true);
        }
    }
}
